#ifndef VEC3_H
#define VEC3_H

#include <array>
#include <string>

#include <utils/config.h>

#include <vectorclass.h>

namespace solar
{
    class Vec3
    {
        public:
            Vec3() = default;
            Vec3(double input_x, double input_y, double input_z)
                : internal_vector_(input_x, input_y, input_z, 0)
            {
            }
            Vec3(const vcl::Vec4d& vec);

            [[nodiscard]] SOLAR_PURE_FUNCTION auto x() const -> double;
            [[nodiscard]] SOLAR_PURE_FUNCTION auto y() const -> double;
            [[nodiscard]] SOLAR_PURE_FUNCTION auto z() const -> double;

            void set_x(double input_x);
            void set_y(double input_y);
            void set_z(double input_z);

            // 运算符重载
            [[nodiscard]] SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto operator-() const -> Vec3;

            auto HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION operator+=(const Vec3& vec) -> Vec3;
            auto HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION operator-=(const Vec3& vec) -> Vec3;
            auto HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION operator*=(const Vec3& vec) -> Vec3;
            auto HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION operator/=(const Vec3& vec) -> Vec3;
            auto HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION operator*=(const double& value) -> Vec3;
            auto HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION operator/=(const double& value) -> Vec3;

            [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto squared_length() const -> double;
            [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto length() const -> double;
            [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto get_unit_vector() const -> Vec3;
            [[nodiscard]] SOLAR_PURE_FUNCTION auto get_vec() const -> vcl::Vec4d;
            [[nodiscard]] SOLAR_PURE_FUNCTION auto data() const -> std::array<double, 3>;
            [[nodiscard]] SOLAR_PURE_FUNCTION auto to_string() const -> std::string;

            // 返回string的样式
            [[nodiscard]] auto toString() const -> std::string;
            static auto fromString(const std::string& input) -> Vec3;
            [[nodiscard]] SOLAR_PURE_FUNCTION auto hasValue() const -> bool;

        private:
            vcl::Vec4d internal_vector_{};
    };

    [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto operator+(const Vec3& vec1, const Vec3& vec2) -> Vec3;
    [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto operator-(const Vec3& vec1, const Vec3& vec2) -> Vec3;
    [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto operator*(const Vec3& vec1, const Vec3& vec2) -> Vec3;
    [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto operator/(const Vec3& vec1, const Vec3& vec2) -> Vec3;
    [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto operator*(const Vec3& vec1, const double& value) -> Vec3;
    [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto operator*(const double& value, const Vec3& vec1) -> Vec3;
    [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto operator/(const Vec3& vec1, const double& value) -> Vec3;
    [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto dot(const Vec3& vec1, const Vec3& vec2) -> double;
    [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto unit_vector(const Vec3& vec) -> Vec3;
    [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto cross(const Vec3& vec1, const Vec3& vec2) -> Vec3;
    /// 矩阵[a, b, c]的行列式
    [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto determinant(const Vec3& vec1, const Vec3& vec2,
                                                 const Vec3& vec3) -> double;
    /// 利用cramer法则求解线性方程组:[a, b, c]·X = Y
    [[nodiscard]] HOT_FUNCTION SOLAR_PURE_FUNCTION FLATTEN_FUNCTION auto cramer(const Vec3& vec1, const Vec3& vec2, const Vec3& vec3,
                                            const Vec3& result) -> Vec3;

} // namespace solar

// 把Vec3声明为元数据，这样就可以把Vec3存到QVariant中

#endif
